package com.chengyu.core.saasopenai;


import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.ResponseEntity;
import org.springframework.util.CollectionUtils;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.util.UriBuilder;
import org.springframework.web.util.UriComponentsBuilder;

import java.net.URI;
import java.net.URLDecoder;
import java.nio.charset.StandardCharsets;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

/**
 * @author wangbo
 * @version 1.0
 * @description 用saas open api http调用工具，不支持参数校验
 * @date 2023/7/21 11:24 AM
 */
@Slf4j
public class SaasOpenApiHttpTool {

    static public ResponseEntity<String> callHttp(OpenApiHttpReq req, SaasOpenApiConfig saasOpenApiConfig, RestTemplate restTemplate)throws Exception{
        UriBuilder uriBuilder = UriComponentsBuilder.fromUriString(req.getUrl());

        if(req.getHeader()==null){
            req.setHeader(new HashMap<>());
        }
        if(req.getUrlParam()==null){
            req.setUrlParam(new HashMap<>());
        }
        if(req.getBody()==null){
            req.setBody("");
        }

        final HttpMethod httpMethod = req.getHttpMethod();
        final HttpHeaders headers = new HttpHeaders();
        final Map<String,String> params = req.getUrlParam();
        URI uri =  uriBuilder.build();
        String contentType = "application/json";
        String canonicalHeaders = "content-type:" + contentType + "\n" + "X-SAAS-HOST:" + uri.getHost()+":"+uri.getPort() + "\n";
        //url入参处理
        //uriBuilder.setCharset(StandardCharsets.UTF_8);

        req.getUrlParam().forEach((k,v)->uriBuilder.queryParam(k,v));
        req.getHeader().forEach((k,v)->headers.add(k,v));


        String canonicalQueryString = resolveQueryString(params);
        String signedHeaders = "content-type;X-SAAS-HOST";
        String timestamp = getTimestamp(req.getTimestamp());

        //进行加密
        String signature = SignatureUtil.sign(httpMethod.name(), uri.getPath(), canonicalQueryString, canonicalHeaders, signedHeaders,
                req.getBody(), saasOpenApiConfig.getAlgorithm(), timestamp, saasOpenApiConfig.getSecretId(), saasOpenApiConfig.getSecretKey());

        String authorization = SignatureUtil.authorization(saasOpenApiConfig.getAlgorithm(), saasOpenApiConfig.getSecretId(), signedHeaders, signature);
        // 设置鉴权参数，如果此参数设置错误，将触发“AGW.xxxxx”类型的错误，详见3.4章节
        headers.add("Content-Type",contentType);
        headers.add("X-SAAS-HOST", uri.getHost()+":"+uri.getPort());
        headers.add("X-SAAS-AUTHORIZATION", authorization);
        headers.add("X-SAAS-TIMESTAMP", timestamp);



        HttpEntity<String> requestEntity = new HttpEntity<>(req.getBody(), headers);
        ResponseEntity<String> resEntity = restTemplate.exchange(uriBuilder.build(), httpMethod, requestEntity, String.class);

//        log.debug("http post call url:{} headers:{} resEntity:{}", uri, headers, (resEntity));
        return resEntity;
    }


    static private String getTimestamp(Date date) {
        return String.valueOf(date.getTime() / 1000);
    }

    /**
     * 解析查询参数字符串
     * @param params 查询参数对象
     */
    static private String resolveQueryString(Map<String,String> params)throws Exception {
        if (CollectionUtils.isEmpty(params)) {
            return "";
        }
        StringBuilder sb = new StringBuilder();
        for (Map.Entry<String, String> entry : params.entrySet()) {
            if(entry.getValue()!=null && !entry.getValue().isEmpty()) {
                sb.append(URLDecoder.decode(entry.getKey(), StandardCharsets.UTF_8.name()))
                        .append("=").append(URLDecoder.decode(entry.getValue(), StandardCharsets.UTF_8.name())).append("&");
            }
        }
        return removeSuffix(sb.toString(), "&");
    }

    static private String removeSuffix(String str, String suffix) {
        if (!StringUtils.isEmpty(str) && !StringUtils.isEmpty(suffix)) {
            return str.endsWith(suffix) ? str.substring(0,str.length() - suffix.length()) : str;
        } else {
            return str;
        }
    }
}
